import { GeneratorsProcess } from "../enum/engine.enum"
import pormiseEnum from "../enum/promise.enum"
class EngineGeneratorResult {
  type: number
  constructor(e: number) {
    this.type = e
  }
}
export class NullGeneratorResult extends EngineGeneratorResult {
  constructor() {
    super(GeneratorsProcess.None)
  }
}
class WaitDurationGeneratorResult extends EngineGeneratorResult {
  duration: number
  startTime: number
  constructor(duration: number) {
    super(GeneratorsProcess.Duration)
    this.duration = duration
    this.startTime = Date.now()
  }
}
class WaitForPhaseGeneratorResult extends EngineGeneratorResult {
  phase: number
  constructor(e: number) {
    super(GeneratorsProcess.Phase)
    this.phase = e
  }
}
export class WaitForPromiseGeneratorResult extends EngineGeneratorResult {
  promiseState: number
  promise: Promise<any>
  constructor(promise: Promise<any>) {
    super(GeneratorsProcess.Promise)
    this.promise = promise
    this.promiseState = pormiseEnum.Pending
    promise
      .then(() => {
        this.promiseState = pormiseEnum.Fulfilled
      })
      .catch(() => {
        this.promiseState = pormiseEnum.Rejected
      })
  }
}
class EngineGenerator {
  generator: () => Generator
  started: boolean
  iterator: Generator
  currentResult: any
  constructor(generator: () => Generator, start = !0) {
    this.generator = generator
    start && this.start()
  }
  start() {
    this.started || (this.iterator = this.generator())
    this.started = !0
  }
  iterate() {
    const e = this.iterator.next()
    this.currentResult = e.value
    e.done && (this.started = !1)
  }
}
export default class EngineGenerators {
  generators: EngineGenerator[]
  constructor() {
    this.generators = []
  }
  startGenerator(e: () => Generator) {
    let t = this.generators.length
    for (let i = 0; i < this.generators.length; i++) {
      this.generators[i].generator === e && (t = i)
    }
    this.generators[t] = new EngineGenerator(e)
  }
  stopGenerator(e: () => Generator) {
    for (const t of this.generators) t.generator === e && (t.started = !1)
  }
  processGenerators(e: number, t?: number) {
    for (const i of this.generators)
      if (i.started) {
        switch (e) {
          case GeneratorsProcess.None:
            ;(!i.currentResult || i.currentResult instanceof NullGeneratorResult) && i.iterate()
            break
          case GeneratorsProcess.Phase:
            if (i.currentResult instanceof WaitForPhaseGeneratorResult) {
              const e = i.currentResult
              void 0 !== t && e.phase === t && i.iterate()
            }
            break
          case GeneratorsProcess.Promise:
            if (i.currentResult instanceof WaitForPromiseGeneratorResult) {
              i.currentResult.promiseState === pormiseEnum.Fulfilled && i.iterate()
            }
            break
          case GeneratorsProcess.Duration:
            if (i.currentResult instanceof WaitDurationGeneratorResult) {
              const e = i.currentResult
              Date.now() - e.startTime >= e.duration && i.iterate()
            }
        }
      }
  }
}
